﻿namespace ImageDupFinder
{
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;

    /// <summary>
    /// System.Windows.Forms Panel with optional lazy loading.
    /// </summary>
    public class LazyPanel : Panel, ImageDupFinder.ILazyLoad
    {
        /// <summary>
        /// set to true if lazy load can be performed, set to false after load.
        /// </summary>
        private bool canLazyLoad = true;

        /// <summary>
        /// User data that can be used during lazy load.
        /// </summary>
        private object lazyData = null;

        /// <summary>
        /// Initializes a new instance of the LazyPanel class.
        /// </summary>
        public LazyPanel()
            : base()
        {
        }

        /// <summary>
        /// Initializes a new instance of the LazyPanel class.
        /// </summary>
        /// <param name="lazyData">user data that can be used during lazy load</param>
        public LazyPanel(object lazyData)
            : this()
        {
            this.lazyData = lazyData;
        }

        /// <summary>
        /// Callback function called when lazy loading is initialized.
        /// </summary>
        [Category("Action"), Browsable(true)]
        public event EventHandler LazyLoadCallback;

        /// <summary>
        /// Gets a value indicating whether lazy loading was performed.
        /// </summary>
        public bool CanLazyLoad
        {
            get { return canLazyLoad; }
        }

        /// <summary>
        /// Gets or sets User data that can be used during lazy loading.
        /// </summary>
        public object LazyData
        {
            get { return lazyData; }
            set { lazyData = value; }
        }

        /// <summary>
        /// Invokes lazy load procedure on all ILazyLoad child controls of this control.
        /// By default this function will load all child controls that are visible in client rectangle.
        /// </summary>
        public virtual void InvokeNestedLazyLoad()
        {
            foreach (Control con in this.Controls)
            {
                ILazyLoad ill = con as ILazyLoad;
                if (ill != null &&
                    ill.CanLazyLoad &&
                    this.ClientRectangle.IntersectsWith(con.Bounds))
                {
                    ill.InvokeLazyLoad();
                }
            }
        }

        /// <summary>
        /// Invokes lazy loading process.
        /// </summary>
        public void InvokeLazyLoad()
        {            
            if (canLazyLoad)
            {
                canLazyLoad = false;

                EventHandler tmp = this.LazyLoadCallback;
                if (tmp != null)
                {
                    tmp(this, null);
                }

                lazyData = null;
            }
        }

        /// <summary>
        /// Raises the MouseWheel event.
        /// Invokes lazy load on nested LazyPanels.
        /// </summary>
        /// <param name="e">Event args</param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            InvokeNestedLazyLoad();
        }

        /// <summary>
        /// Raises the Scroll event.
        /// Invokes lazy load on nested LazyPanels.
        /// </summary>
        /// <param name="se">Event args</param>
        protected override void OnScroll(ScrollEventArgs se)
        {
            base.OnScroll(se);
            InvokeNestedLazyLoad();
        }
    }
}
